﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using KTool2.Core;
using System.Threading;
using KTool2.Utility;
using System.Collections.ObjectModel;
using KTool2.Common;
using KTool2.Impl;

namespace KTool2
{
    /// <summary>
    /// Interaction logic for TestWindow.xaml
    /// </summary>
    public partial class TestWindow : Window
    {
        private static volatile TestWindow instance;
        private IKanjiWordList kWordList;
        private KanjiWord curKWord;
        private int shownItem = 0;
        private int rightItem = 0;
        private int evaluateResult = 0;
        private StringBuilder accuracyBuilder = new StringBuilder("Accuracy: 0/0");
        private StringBuilder answerHiraganaBuilder = new StringBuilder(10, 20);
        private StringBuilder inputHiraganaBuilder = new StringBuilder(10, 20);
        private System.Windows.Threading.DispatcherTimer tmrEvaluate;

        public static TestWindow Instance
        {
            get
            {
                if (instance == null)
                {
                    Mutex mutex = new Mutex();
                    mutex.WaitOne();

                    if (instance == null)
                    {
                        instance = new TestWindow();
                    }

                    mutex.Close();
                }

                return instance;
            }
        }

        public static bool IsNull
        {
            get { return instance == null; }
        }

        protected TestWindow()
        {
            InitializeComponent();

            this.tmrEvaluate = new System.Windows.Threading.DispatcherTimer();
            this.tmrEvaluate.Interval = TimeSpan.FromSeconds(0.001);
            this.tmrEvaluate.Tick += new EventHandler(tmrEvaluate_Tick);

            InitJPNCategoriesMenuItem();
            InitKanjiWordList();
        }

        void tmrEvaluate_Tick(object sender, EventArgs e)
        {
            if (this.prgrsEvaluation.Value < this.evaluateResult)
            {
                if (this.evaluateResult - this.prgrsEvaluation.Value == 1)
                {
                    this.prgrsEvaluation.Value += 1;
                }
                else
                {
                    this.prgrsEvaluation.Value += 2;
                }
            }
            else if (this.prgrsEvaluation.Value > this.evaluateResult)
            {
                if (this.prgrsEvaluation.Value - this.prgrsEvaluation.Value == 1)
                {
                    this.prgrsEvaluation.Value -= 1;
                }
                else
                {
                    this.prgrsEvaluation.Value -= 2;
                }
            }
            else
            {
                this.StopEvaluateTimer();
            }
        }

        private void StopEvaluateTimer()
        {
            this.tmrEvaluate.Stop();
            if (this.evaluateResult < 100)
            {
                this.txtKanji.Background = Brushes.Red;
            }
            else
            {
                if (this.txtKanji.Background != Brushes.Red)
                {
                    ++this.rightItem;
                    this.SetAccuracyStatus();
                }

                this.ShowAnswerHiragana();
            }
        }

        private void ShowAnswerHiragana()
        {
            this.btnShowAnswer.Height = 0;
            this.btnShowAnswer.Width = 0;
            this.txtAnswerHiragana.Text = this.curKWord.Hiragana;
            this.lbltltpEnglish.Content = this.curKWord.English;
            this.lbltltpHanNom.Content = this.curKWord.HanNom;
            this.lbltltpHiragana.Content = this.curKWord.Hiragana;
            this.lbltltpMeaning.Content = this.curKWord.Viet;
            this.btnOK.IsEnabled = false;
            this.btnNext.Focus();
        }

        private void InitKanjiWordList()
        {
            string category = null;
            int memrate = 0;

            foreach (var item in this.mnuiJPNCategories.Items)
            {
                if (item is MenuItem && (item as MenuItem).IsChecked)
                {
                    category = (item as MenuItem).Header.ToString();
                    break;
                }
            }

            foreach (var item in this.mnuiMemrate.Items)
            {
                if (item is MenuItem && (item as MenuItem).IsChecked)
                {
                    memrate = (item as MenuItem).Name[7] - '0';
                    break;
                }
            }

            if (memrate < 1 || memrate > 5) // invalid memrate
            {
                if (Constant.ALL_CATEGORIES.Equals(category))
                {
                    this.kWordList = KanjiWordListProcessor.GetAllKanjiWord();
                }
                else
                {
                    this.kWordList = KanjiWordListProcessor.GetKanjiWordList(category);
                }
            }
            else
            {
                if (Constant.ALL_CATEGORIES.Equals(category))
                {
                    this.kWordList = KanjiWordListProcessor.GetAllKanjiWord(memrate);
                }
                else
                {
                    this.kWordList = KanjiWordListProcessor.GetKanjiWordList(category, memrate);
                }
            }

            if (this.kWordList.Count == 0)
            {
                MessageBox.Show("Database return no kanji word that based on your setting.\nPlease choose your setting again."
                    , "No word found", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                this.btnNext.IsEnabled = false;
                this.btnOK.IsEnabled = false;
                this.btnShowAnswer.IsEnabled = false;
                this.txtKanji.Text = "";
                this.SetMemrateImage(0);
                this.txtTotal.Text = string.Format("Total: {0}", this.kWordList.Count.ToString());
            }
            else
            {
                this.kWordList.Shuffle();
                this.ShowNextWord();
            }
        }

        private void GetNextWord()
        {
            if (this.mnuiFairRandom.IsChecked)
            {
                this.curKWord = this.kWordList.FairRanDomKanji;
            }
            else
            {
                this.curKWord = this.kWordList.RanDomKanji;
            }
        }

        private void ShowNextWord()
        {
            this.GetNextWord();

            this.txtKanji.Text = this.curKWord.Kanji;
            this.SetMemrateImage(this.curKWord.MemRate);
            this.txtHiragana.Text = "";
            this.txtHiragana.Focus();

            this.btnShowAnswer.Height = 28;
            this.btnShowAnswer.Width = 40;
            this.txtAnswerHiragana.Text = "";
            this.lbltltpEnglish.Content = Constant.MYSTERIOUS;
            this.lbltltpHanNom.Content = Constant.MYSTERIOUS;
            this.lbltltpHiragana.Content = Constant.MYSTERIOUS;
            this.lbltltpMeaning.Content = Constant.MYSTERIOUS;
            this.txtTotal.Text = string.Format("Total: {0}", this.kWordList.Count.ToString());

            this.prgrsEvaluation.Value = 0;
            this.txtKanji.Background = Brushes.Transparent;

            this.btnNext.IsEnabled = true;
            this.btnOK.IsEnabled = true;
            this.btnShowAnswer.IsEnabled = true;

            ++this.shownItem;
            this.SetAccuracyStatus();
        }

        private void SetAccuracyStatus()
        {
            this.accuracyBuilder.Remove(10, this.accuracyBuilder.Length - 10);
            this.accuracyBuilder.Append(this.rightItem).Append('/').Append(this.shownItem);
            this.txtAccuracy.Text = accuracyBuilder.ToString();
        }

        private void SetMemrateImage(int memrate)
        {
            this.rate1.Source = ImageManager.Dot;
            this.rate2.Source = ImageManager.Dot;
            this.rate3.Source = ImageManager.Dot;
            this.rate4.Source = ImageManager.Dot;
            this.rate5.Source = ImageManager.Dot;

            this.rate1.Height = 10;
            this.rate2.Height = 10;
            this.rate3.Height = 10;
            this.rate4.Height = 10;
            this.rate5.Height = 10;

            if (memrate >= 1)
            {
                this.rate1.Source = ImageManager.Rate;
                this.rate1.Height = 22;
            }

            if (memrate >= 2)
            {
                this.rate2.Source = ImageManager.Rate;
                this.rate2.Height = 22;
            }

            if (memrate >= 3)
            {
                this.rate3.Source = ImageManager.Rate;
                this.rate3.Height = 22;
            }

            if (memrate >= 4)
            {
                this.rate4.Source = ImageManager.Rate;
                this.rate4.Height = 22;
            }

            if (memrate >= 5)
            {
                this.rate5.Source = ImageManager.Rate;
                this.rate5.Height = 22;
            }
        }

        private void InitJPNCategoriesMenuItem()
        {
            string[] tableArray = Database.DBManagement.TableArray;
            MenuItem category = null;

            foreach (var table in tableArray)
            {
                category = new MenuItem();
                category.Name = "mnuiJPNCategory" + table.Replace('#', '_')
                    .Replace(' ', '_').Substring(0, table.Length - 1);
                category.Header = table.Replace('#', '.');
                category.IsCheckable = true;
                //category.IsChecked = true;
                //category.Checked += mnui_Checked;
                //category.Unchecked += mnui_Unchecked;
                category.Click += this.mnui_Click;

                this.mnuiJPNCategories.Items.Add(category);
            }

            this.mnuiJPNCategories.Items.Add(new Separator());
            category = new MenuItem();
            category.Name = "mnuiJPNCategory" + Constant.ALL_CATEGORIES.Replace('#', '_').Replace(' ', '_');
            category.Header = Constant.ALL_CATEGORIES;
            category.IsCheckable = true;
            category.IsChecked = true;
            //category.Checked += mnui_Checked;
            //category.Unchecked += mnui_Unchecked;
            category.Click += this.mnui_Click;
            this.mnuiJPNCategories.Items.Add(category);
        }

        private void Evaluate()
        {
            int rightPosition = 0;
            int rightCharacter = 0;
            double rightPositionRate = 0.0;
            double rightCharacterRate = 0.0;
            double redundantRate = 0.0;
            this.answerHiraganaBuilder.Clear();
            this.inputHiraganaBuilder.Clear();
            this.answerHiraganaBuilder.Append(this.curKWord.Hiragana.Trim().ToUpper());
            this.inputHiraganaBuilder.Append(this.txtHiragana.Text.Trim().ToUpper());

            for (int i = 0; i < this.answerHiraganaBuilder.Length; i++)
            {
                if (i < this.inputHiraganaBuilder.Length 
                    && this.inputHiraganaBuilder[i] == this.answerHiraganaBuilder[i])
                {
                    ++rightPosition;
                }
            }

            for (int i = 0; i < this.inputHiraganaBuilder.Length; i++)
            {
                for (int j = 0; j < this.answerHiraganaBuilder.Length; j++)
                {
                    if (this.inputHiraganaBuilder[i] == this.answerHiraganaBuilder[j])
                    {
                        this.answerHiraganaBuilder[j] = '*';
                        ++rightCharacter;
                        break;
                    }
                }
            }

            if (rightPosition == this.inputHiraganaBuilder.Length)
            {
                this.evaluateResult = 100;
            }
            //else
            //{
            //    for (int i = 0; i < this.inputHiraganaBuilder.Length; i++)
            //    {
            //        for (int j = 0; j < this.answerHiraganaBuilder.Length; j++)
            //        {
            //            if (this.inputHiraganaBuilder[i] == this.answerHiraganaBuilder[j])
            //            {
            //                this.answerHiraganaBuilder[j] = '*';
            //                ++rightCharacter;
            //                break;
            //            }
            //        }
            //    }
            //}

            rightPositionRate = (double)rightPosition / this.answerHiraganaBuilder.Length;
            redundantRate = (double)(this.inputHiraganaBuilder.Length - rightCharacter)
                / this.answerHiraganaBuilder.Length / 3;
            //redundantRate = (double)(this.inputHiraganaBuilder.Length - this.answerHiraganaBuilder.Length)
            //    / this.answerHiraganaBuilder.Length / 2;
            rightCharacterRate = (double)(rightCharacter - rightPosition) 
                / (this.answerHiraganaBuilder.Length - rightPosition) / 3;

            this.evaluateResult = (int)((redundantRate > 0 ? rightPositionRate - redundantRate : rightPositionRate
                + (rightCharacterRate > 0 ? rightCharacterRate : 0)) * 100);
        }

        private void btn_Click(object sender, RoutedEventArgs e)
        {
            switch ((sender as Button).Name)
            { 
                case "btnOK":
                    this.Evaluate();
                    this.tmrEvaluate.Start();
                    break;
                case "btnNext":
                    ShowNextWord();
                    break;
                case "btnShowAnswer":
                    this.ShowAnswerHiragana();
                    break;
            }
        }

        private void mnui_Click(object sender, RoutedEventArgs e)
        {
            if ((sender as MenuItem).Name.StartsWith("mnuiJPNCategory")) // Sub-Menu item of categories is clicked
            {
                foreach (var item in this.mnuiJPNCategories.Items)
                {
                    if (item is MenuItem && !(item as MenuItem).Name.Equals((sender as MenuItem).Name))
                    {
                        (item as MenuItem).IsChecked = false;
                    }
                }
            }
            else if ((sender as MenuItem).Name.StartsWith("mnuiMrt")) // Sub-Menu item of memrate is clicked
            {
                foreach (var item in this.mnuiMemrate.Items)
                {
                    if (item is MenuItem && !(item as MenuItem).Name.Equals((sender as MenuItem).Name))
                    {
                        (item as MenuItem).IsChecked = false;
                    }
                }
            }
            else
            {
                return;
            }

            this.InitKanjiWordList();

            if (this.shownItem > 1)
            {
                --this.shownItem;
                this.SetAccuracyStatus();
            }
        }

        private void Rectangle_MouseDown(object sender, MouseButtonEventArgs e)
        {
            this.txtHiragana.Focus();
        }

        protected override void OnClosed(EventArgs e)
        {
            instance = null;
            base.OnClosed(e);
        }

        private void rate_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (((Image)sender).Name[4] - '0' != this.curKWord.MemRate)
            {
                //this.kWordList.SetMemrate(this.curKWord, ((Image)sender).Name[4] - '0');
                this.curKWord.MemRate = ((Image)sender).Name[4] - '0';

                if (((Image)sender).Name[4] - '0' != this.SelectedMemrate)
                {
                    switch (this.SelectedMemrate)
                    { 
                        case 1:
                        case 2:
                            this.kWordList.LowList.Remove(this.curKWord);
                            break;
                        case 3:
                        case 4:
                            this.kWordList.MediumList.Remove(this.curKWord);
                            break;
                        case 5:
                            this.kWordList.HighList.Remove(this.curKWord);
                            break;
                    }
                }
            }

            this.SetMemrateImage(((Image)sender).Name[4] - '0');
            this.txtTotal.Text = string.Format("Total: {0}", this.kWordList.Count.ToString());
        }

        /// <summary>
        /// Returns current selected memrate from the Memrate menu, 6 if 'All Memrate' is checked
        /// </summary>
        private int SelectedMemrate
        {
            get
            {
                for (int i = 0; i < this.mnuiMemrate.Items.Count; i++)
                {
                    if (this.mnuiMemrate.Items[i] is MenuItem
                        && (this.mnuiMemrate.Items[i] as MenuItem).IsChecked)
                    {
                        if ((this.mnuiMemrate.Items[i] as MenuItem).Name[7] >= '1'
                            && (this.mnuiMemrate.Items[i] as MenuItem).Name[7] <= '5')
                        {
                            return (this.mnuiMemrate.Items[i] as MenuItem).Name[7] - '0';
                        }
                        else // 'All Memrate' is selected
                        {
                            return 6;
                        }
                    }
                }

                return -1;
            }
        }
    }
}
